<%@import=java.io.File%>
<%@import=java.util.Map%>
<%@import=lpg.util.Utility%>
//--<%=parserFile.getAbsolutePath()%>
//
// DO NOT MODIFY THIS FILE - it is generated using optionpg on lpg.OptionEnum
//
package lpg;

class OptionParser
{
    OptionParser(Option option, char[] param, int end)
    {
        this.option = option;
        this.param = param;
        this.end = end;
    }

    int classifyOption(int start, boolean flag)
    {
        int p = start;
        char c = param[start];<%
        processOptionPath(optionMap);
        %>
    }
<%

        for (Node node : optionMap.values())
        {
            processNode(node);
        }

        %>
    private final Option option;
    private final char[] param;
    private final int end;

}
<%!
    private final Map<Character, Node> optionMap;
    private final File parserFile;

    %><%@classname%><%(Map<Character, Node> optionMap, File parserFile, PrintWriter writer)
    {
        this.optionMap = optionMap;
        this.parserFile = parserFile;
        setOut(writer);
    }

    private void processOptionPath(Map<Character, Node> nodeMap)
    {
        %>
        switch (c)
        {<%
        for (Map.Entry<Character, Node> entry : nodeMap.entrySet())
        {
            char c = entry.getKey();
            Node node = entry.getValue();
            if (node.pathSet == null)
            {
                %>
            case '<%=c%>': case '<%=Utility.toLowerCase(c)%>':<%
                // The first char has been classified by the switch
                processSimplePath(node.path.substring(1), node.name, node.isLeaf());
            }
            else
            {
                for (Map.Entry<Character, PathElement> pathEntry : node.pathSet.elemMap.entrySet())
                {
                    char ch = pathEntry.getKey();
                    PathElement element = pathEntry.getValue();

                    String varName = node.name.substring(0, node.name.length() - 1) + ch;
                    String methodName = node.name + "s";
                    // The first char has been classified by the switch
                    String path = element.path.substring(1);

                    %>
            case '<%=ch%>': case '<%=Utility.toLowerCase(ch)%>':<%

                    String branchPath = null;
                    if (element.branchSet.isEmpty())
                    {
                        processSimplePath(path, methodName, true);
                    }
                    else if ((branchPath = element.getSingleBranchPath()) != null)
                    {
                        // The first char has been classified by the switch
                        int length = element.getSingleBranchPrefixLength() - 1;
                        %>
                int i<%=varName%> = Util.prefixMatch(param, ++p, end, "<%=path%>", "<%=Utility.toLowerCase(path)%>");
                return classify<%=methodName%>(start, (i<%=varName%> == <%=length%> ? Util.prefixMatch(param, p + i<%=varName%>, end, "<%=branchPath%>", "<%=Utility.toLowerCase(branchPath)%>") : 0) + p + i<%=varName%>, flag);<%
                    }
                    else
                    {
                        %>
                <%
                        checkPathElement(element, path, "            ", varName, true);
                        %>
                return classify<%=methodName%>(start, p, flag);<%
                    }
                }
            }
        }
        %>
            default:
                return option.classifyBadOption(param, start, end, flag);
        }<%
    }

    private void processSimplePath(String path, String name, boolean isLeaf)
    {
        if (path.length() == 0)
        {
            %>
                return classify<%=name%>(start, ++p, flag);<%
        }
        else if (isLeaf)
        {
            %>
                return classify<%=name%>(start, Util.prefixMatch(param, ++p, end, "<%=path%>", "<%=Utility.toLowerCase(path)%>") + p, flag);<%
        }
        else
        {
            %>
                int i<%=name%> = Util.prefixMatch(param, ++p, end, "<%=path%>", "<%=Utility.toLowerCase(path)%>");
                return classify<%=name%>(start, p + i<%=name%>, flag, i<%=name%> == <%=path.length()%>);<%
        }
    }

    private void processNode(Node node)
    {
        String methodName = (node.pathSet == null) ? node.name : node.name + "s";
        boolean needCheckClassifyChildren =
                node.path != null && node.path.length() > 1 && !node.isLeaf();
        %>
    int classify<%=methodName%>(int start, int p, boolean flag<%
        if (needCheckClassifyChildren)
        {
            %>, boolean classifyChildren<%
        }
        %>)
    {
        char c;
        if (p == end || (c = param[p]) == '=' || Option.isDelimiter(c))
        {
            <%
        processClassifiedOptionSet(node);
        %>
        }<%

        if (node.isLeaf())
        {
            %>
        return option.classifyBadOption(param, start, end, flag);<%
        }
        else
        {
            if (needCheckClassifyChildren)
            {
                %>
        if (!classifyChildren)
        {
            return option.classifyBadOption(param, start, end, flag);
        }<%
            }
            processOptionPath(node.children);
        }
        %>
    }
<%

        if (!node.isLeaf())
        {
            for (Node childNode : node.children.values())
            {
                processNode(childNode);
            }
        }
    }

    private void checkPathSet(PathSet pathSet, String indent, String varName)
    {
        boolean first = true;
        for (Map.Entry<Character, PathElement> entry : pathSet.elemMap.entrySet())
        {
            PathElement element = entry.getValue();
            %>
<%=indent%><%
            if (first)
            {
                first = false;
            }
            else
            {
                %>else <%
            }
            checkPathElement(element, element.path, indent, varName, false);
        }
    }

    private void checkPathElement(PathElement element, String path, String indent, String varName, boolean root)
    {
        if (root)
        {
            %>int <%
        }
        else
        {
            %>if ((<%
        }
        %>i<%=varName%> = Util.prefixMatch(param, p, end, "<%=path%>", "<%=Utility.toLowerCase(path)%>")<%
        if (root)
        {
            %>;
                <%
        }
        else
        {
            %>) > 0)
<%=indent%>{
<%=indent%>    <%
        }
        %>p += i<%=varName%>;<%

        boolean first = true;
        for (Map.Entry<Integer, PathSet> entry : element.branchSet.entrySet())
        {
            // The first char has been classified by the switch
            int len = root ? entry.getKey() - 1: entry.getKey();
            %>
<%=indent%>    <%
            if (first)
            {
                first = false;
            }
            else
            {
                %>else <%
            }
            %>if (i<%=varName%> == <%=len%>)
<%=indent%>    {<%
            checkPathSet(entry.getValue(), indent + "        ", varName);
            %>
<%=indent%>    }<%
        }
        if (!root)
        {
            %>
<%=indent%>}<%
        }
    }

    private void processClassifiedOptionSet(Node node)
    {
        if (node.switchOptionCount > 0 || node.valuedOptionCount == 1)
        {
            %>int q = <%
        }
        %>Option.valuedOption(param, p, end);
            <%
        if (node.switchOptionCount == 0)
        {
            if (node.valuedOptionCount == 1)
            {
                %>return flag ? q < 0 ? option.reportMissingValue(param, start, end)
                                : OptionEnum.<%=node.valuedOption%>.setValue(param, start, end, p, q, option)
                        : option.classifyBadOption(param, start, end, false);<%
            }
            else
            {
                %>return flag ? option.reportAmbiguousOption(param, start, end, true, "<%=Control.toString(node.optionSet)%>")
                        : option.classifyBadOption(param, start, end, false);<%
            }
        }
        else if (node.switchOptionCount == 1)
        {
            if (node.valuedOptionCount == 0)
            {
                %>return q < 0 ? OptionEnum.<%=node.switchOption%>.setBooleanValue(flag, p, option)
                         : flag ? option.reportValueNotRequired(param, start, end)
                                : option.classifyBadOption(param, start, end, false);<%
            }
            else if (node.valuedOptionCount == 1)
            {
                %>return q < 0 ? OptionEnum.<%=node.switchOption%>.setBooleanValue(flag, p, option)
                         : flag ? OptionEnum.<%=node.valuedOption%>.setValue(param, start, end, p, q, option)
                                : option.classifyBadOption(param, start, end, false);<%
            }
            else
            {
                %>return flag ? option.reportAmbiguousOption(param, start, end, true, "<%=Control.toString(node.optionSet)%>")
                        : q < 0 ? OptionEnum.<%=node.switchOption%>.setBooleanValue(false, p, option)
                                : option.classifyBadOption(param, start, end, false);<%
            }
        }
        else
        {
            if (node.valuedOptionCount == 1)
            {
                %>return q < 0 ? option.reportAmbiguousOption(param, start, end, flag, "<%=Control.toString(node.optionSet)%>")
                         : flag ? OptionEnum.<%=node.valuedOption%>.setValue(param, start, end, p, q, option)
                                : option.classifyBadOption(param, start, end, false);<%
            }
            else
            {
                %>return (q < 0 || flag) ? option.reportAmbiguousOption(param, start, end, flag, "<%=Control.toString(node.optionSet)%>")
                                   : option.classifyBadOption(param, start, end, false);<%
            }
        }
    }
%>
